---
title: "Session Service"
description: "Coordinates session-related functionality across the system"
---

## Overview

The Session Service is the central coordinator for user session management in MentraOS Cloud. It handles session creation, retrieval, and transformation while delegating specialized tasks to the UserSession class and its managers.

**File**: `packages/cloud/src/services/session/session.service.ts`

## Key Responsibilities

1. **Session Lifecycle Management**: Creating and retrieving sessions
2. **Message Routing**: Relaying messages between glasses and apps
3. **Settings Management**: User and app-specific settings
4. **Session Transformation**: Preparing session data for clients
5. **Audio Routing**: Directing audio data to appropriate handlers

## Session Creation

The service creates or retrieves sessions with automatic reconnection handling:

```typescript
async createSession(ws: WebSocket, userId: string): Promise<{ 
  userSession: UserSession, 
  reconnection: boolean 
}> {
  // Check for existing session
  const existingSession = UserSession.getById(userId);
  
  if (existingSession) {
    // Reconnection scenario
    existingSession.updateWebSocket(ws);
    existingSession.disconnectedAt = null;
    
    // Clear cleanup timer
    if (existingSession.cleanupTimerId) {
      clearTimeout(existingSession.cleanupTimerId);
      existingSession.cleanupTimerId = undefined;
    }
    
    return { userSession: existingSession, reconnection: true };
  }
  
  // Create new session
  const userSession = new UserSession(userId, ws);
  
  // Fetch and populate installed apps
  const installedApps = await appService.getAllApps(userId);
  for (const app of installedApps) {
    userSession.installedApps.set(app.packageName, app);
  }
  
  return { userSession: userSession, reconnection: false };
}
```

### Reconnection Handling

When a user reconnects:
- Existing session is preserved
- WebSocket connection is updated
- Cleanup timers are cancelled
- Disconnection timestamp is cleared

## Session Retrieval

Multiple methods for accessing sessions:

```typescript
// By session ID
getSession(sessionId: string): UserSession | null

// By user ID (email)
getSessionByUserId(userId: string): UserSession | null

// All active sessions
getAllSessions(): UserSession[]
```

## Session Transformation

Prepares session data for client consumption with calculated requirements:

```typescript
async transformUserSessionForClient(userSession: UserSession): Promise<any> {
  // Collect app subscriptions
  const appSubscriptions: Record<string, string[]> = {};
  for (const packageName of userSession.runningApps) {
    appSubscriptions[packageName] = subscriptionService.getAppSubscriptions(
      userId, 
      packageName
    );
  }
  
  // Calculate stream requirements
  const hasPCMTranscriptionSubscriptions = 
    subscriptionService.hasPCMTranscriptionSubscriptions(userId);
  const requiresAudio = hasPCMTranscriptionSubscriptions.hasMedia;
  
  // Update microphone state based on requirements
  const requiredData = userSession.microphoneManager.calculateRequiredData(
    hasPCMTranscriptionSubscriptions.hasPCM, 
    hasPCMTranscriptionSubscriptions.hasTranscription
  );
  userSession.microphoneManager.updateState(requiresAudio, requiredData);
  
  return {
    userId,
    startTime: userSession.startTime,
    activeAppSessions: Array.from(userSession.runningApps),
    loadingApps: Array.from(userSession.loadingApps),
    appSubscriptions,
    requiresAudio,
    minimumTranscriptionLanguages,
    isTranscribing: userSession.isTranscribing || false
  };
}
```

## Message Routing

### Relay to Apps

Routes messages from glasses to subscribed apps:

```typescript
relayMessageToApps(userSession: UserSession, data: GlassesToCloudMessage): void {
  // Get subscribed apps
  const subscribedPackageNames = subscriptionService.getSubscribedApps(
    userSession, 
    data.type
  );
  
  // Send to each subscriber
  for (const packageName of subscribedPackageNames) {
    const connection = userSession.appWebsockets.get(packageName);
    
    if (connection && connection.readyState === WebSocket.OPEN) {
      const dataStream: DataStream = {
        type: CloudToAppMessageType.DATA_STREAM,
        sessionId: `${userSession.sessionId}-${packageName}`,
        streamType: data.type as StreamType,
        data,
        timestamp: new Date()
      };
      
      connection.send(JSON.stringify(dataStream));
    }
  }
}
```

### Audio Routing

Delegates audio processing to the AudioManager:

```typescript
relayAudioToApps(userSession: UserSession, audioData: ArrayBuffer): void {
  userSession.audioManager.processAudioData(audioData, false);
}
```

### Audio Response Routing

Routes audio play responses back to requesting apps:

```typescript
relayAudioPlayResponseToApp(userSession: UserSession, audioResponse: any): void {
  const requestId = audioResponse.requestId;
  
  // Find which app made the request
  const packageName = userSession.audioPlayRequestMapping.get(requestId);
  
  if (packageName) {
    const connection = userSession.appWebsockets.get(packageName);
    // Send response to app...
  }
}
```

## Settings Management

### User Settings

Retrieves combined system and app settings:

```typescript
async getUserSettings(userId: string): Promise<Record<string, any>> {
  const user = await User.findOne({ email: userId });
  
  if (!user) {
    return DEFAULT_AUGMENTOS_SETTINGS;
  }
  
  // Get system settings
  const augmentosSettings = user.getAugmentosSettings();
  
  // Add app settings
  const allSettings = {
    ...augmentosSettings,
    appSettings: Object.fromEntries(user.appSettings || new Map())
  };
  
  return allSettings;
}
```

### App-Specific Settings

```typescript
async getAppSettings(userId: string, packageName: string): Promise<Record<string, any>> {
  const allSettings = await this.getUserSettings(userId);
  return allSettings.appSettings?.[packageName] || {};
}
```

## Default Settings

System default settings when user settings are not available:

```typescript
const DEFAULT_AUGMENTOS_SETTINGS = {
  useOnboardMic: false,
  contextualDashboard: true,
  headUpAngle: 20,
  brightness: 50,
  autoBrightness: false,
  sensingEnabled: true,
  alwaysOnStatusBar: false,
  bypassVad: false,
  bypassAudioEncoding: false,
  metricSystemEnabled: false
};
```

## Error Handling

- **Session Creation**: Logs errors and re-throws for upstream handling
- **Message Routing**: Catches and logs send errors per app
- **Settings Retrieval**: Returns defaults on error
- **Transformation**: Returns minimal data on error

## Integration Points

- **UserSession**: Core session object creation and management
- **SubscriptionService**: Determining app subscriptions and requirements
- **AppService**: Fetching installed apps
- **User Model**: Database access for settings
- **AudioManager**: Audio data processing
- **MicrophoneManager**: Microphone state management

## Best Practices

1. **Always check WebSocket state** before sending messages
2. **Handle reconnections gracefully** by preserving session state
3. **Return sensible defaults** when data is unavailable
4. **Log errors with context** for debugging
5. **Delegate specialized tasks** to appropriate managers

## Related Documentation

- **[UserSession Class](/cloud-architecture/session-management/user-session-class)**: Core session implementation
- **[SubscriptionService](/cloud-architecture/services/subscription-service)**: Subscription management
- **[AudioManager](/cloud-architecture/managers/audio-manager)**: Audio processing
- **[WebSocketService](/cloud-architecture/services/websocket-service)**: Connection management